package ru.myrtle.umf.codegen.java;

import java.io.BufferedReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

public class JavaDocBuilder {

    public static final String DOC_TAG_VERSION = "version";

    private String indent = "";

    private StringBuilder writer;

    public JavaDocBuilder() {
        initWriter();
    }

    private void initWriter() {
        writer = new StringBuilder();
    }

    public void appendVersion(String doc) {
        append(indent + "\n@" + DOC_TAG_VERSION + ' ' + doc);
    }

    public void append(String doc) {
        if (doc == null)
            return;

        String[] docStrings = doc.split("\n");

        for (String docString : docStrings) {
            docString = docString.trim();

            try {
                writer.append(new String(docString.getBytes(), "Cp1251"));
                writer.append("\n");
            }
            catch (UnsupportedEncodingException e) {
                //
            }
        }
    }

    public void appendJavaDocAnnotation(String name, String param, String description) {
        if (name != null && name.length() > 0) {
            append(indent +
                    "\n@" + name + "\t" +
                    ((param == null) ? "" : param) + "\t" +
                    ((description == null) ? "" : description)
            );
        }
    }

    private HashMap<String, HashMap<String, String>> annotations;

    public void appendAnnotation(String annotationName) {
        appendAnnotation(annotationName, null, null);
    }

    public synchronized void appendAnnotation(String annotationName, String annotationEntryName, String value) {
        if (annotations == null)
            annotations = new HashMap<String, HashMap<String, String>>();

        if (annotationName == null || annotationName.length() == 0)
            return;

        if (!annotations.containsKey(annotationName)) {
            annotations.put(annotationName, new HashMap<String, String>());
        }

        if (annotationEntryName != null && annotationEntryName.length() > 0) {
            annotations.get(annotationName).put(annotationEntryName, value);
        }
    }

    public void appendAnnotation(ru.myrtle.umf.codegen.java.JavaDocAnnotation annotation) {
        append(indent + "\n@" + annotation.getName());

        for (Iterator iterator = annotation.getKeys(); iterator.hasNext();) {
            String key = (String) iterator.next();
            append(indent + "        " + key + "=\"" + annotation.getValue(key) + "\"");
        }
    }

    public void clean() {
        writer.setLength(0);

        if (annotations != null) {
            annotations.clear();
        }

        indent = "";
    }

    public String toString() {
        if (annotations != null && annotations.size() > 0) {
            for (String name : annotations.keySet()) {
                ru.myrtle.umf.codegen.java.JavaDocAnnotation annotation = new ru.myrtle.umf.codegen.java.JavaDocAnnotation(name);

                Set<Entry<String, String>> entrys = annotations.get(name).entrySet();

                for (Entry<String, String> entry : entrys) {
                    annotation.addEntry(entry.getKey(), entry.getValue());
                }

                appendAnnotation(annotation);
            }
        }

        StringBuffer buffer = new StringBuffer(indent + "/**");

        BufferedReader reader = new BufferedReader(
                new StringReader(
                        writer.toString()
                )
        );

        try {
            try {
                String line = "";

                while ((line = reader.readLine()) != null) {
                    buffer.append("\n" + indent + " * ");
                    buffer.append(line);
                }

                buffer.append("\n" + indent + " */");
            }
            finally {
                reader.close();
            }
        }
        catch (Exception thrown) {
            throw new RuntimeException(thrown);
        }

        return buffer.toString();
    }

    public String getIndent() {
        return indent;
    }

    public void setIndent(String indent) {
        this.indent = indent;
    }
}
